
#include "Vector2.h"
#include "RMatrix.h"

using namespace Riccsson::System;
using namespace Riccsson::Xna::Framework;

const Vector2 Vector2::Zero;
const Vector2 Vector2::One(1);
const Vector2 Vector2::UnitX(1, 0);
const Vector2 Vector2::UnitY(0, 1);

#pragma region Constructors

Vector2::Vector2()
{
	X = 0;
	Y = 0;
}

Vector2::Vector2(float x, float y)
{
	X = x;
	Y = y;
}
		 
Vector2::Vector2(float value)
{
	X = value;
	Y = value;
}

#pragma endregion Constructors


#pragma region Vector2::Methods

Vector2 Vector2::Add(Vector2 value1, Vector2 value2)
{
	value1.X += value2.X;
	value1.Y += value2.Y;
	return value1;
}

void Vector2::Add(Vector2 ref value1, Vector2 ref value2, Vector2 out result)
{
	result.X = value1.X + value2.X;
	result.Y = value1.Y + value2.Y;
}

Vector2 Vector2::Barycentric(Vector2 value1, Vector2 value2, Vector2 value3, float amount1, float amount2)
{
	return Vector2(
		MathHelper::Barycentric(value1.X, value2.X, value3.X, amount1, amount2),
		MathHelper::Barycentric(value1.Y, value2.Y, value3.Y, amount1, amount2));
}

void Vector2::Barycentric(Vector2 ref value1, Vector2 ref value2, Vector2 ref value3, float amount1, float amount2, Vector2 out result)
{
	result = Vector2(
		MathHelper::Barycentric(value1.X, value2.X, value3.X, amount1, amount2),
		MathHelper::Barycentric(value1.Y, value2.Y, value3.Y, amount1, amount2));
}

Vector2 Vector2::CatmullRom(Vector2 value1, Vector2 value2, Vector2 value3, Vector2 value4, float amount)
{
	return Vector2(
		MathHelper::CatmullRom(value1.X, value2.X, value3.X, value4.X, amount),
		MathHelper::CatmullRom(value1.Y, value2.Y, value3.Y, value4.Y, amount));
}

void Vector2::CatmullRom(Vector2 ref value1, Vector2 ref value2, Vector2 ref value3, Vector2 ref value4, float amount, Vector2 out result)
{
	result = Vector2(
		MathHelper::CatmullRom(value1.X, value2.X, value3.X, value4.X, amount),
		MathHelper::CatmullRom(value1.Y, value2.Y, value3.Y, value4.Y, amount));
}

Vector2 Vector2::Clamp(Vector2 value1, Vector2 min, Vector2 max)
{
	return Vector2(
		MathHelper::ClampF(value1.X, min.X, max.X),
		MathHelper::ClampF(value1.Y, min.Y, max.Y));
}

void Vector2::Clamp(Vector2 ref value1, Vector2 ref min, Vector2 ref max, Vector2 out result)
{
	result = Vector2(
		MathHelper::ClampF(value1.X, min.X, max.X),
		MathHelper::ClampF(value1.Y, min.Y, max.Y));
}

float Vector2::Distance(Vector2 value1, Vector2 value2)
{
	float v1 = value1.X - value2.X, v2 = value1.Y - value2.Y;
	return (float)Riccsson::System::Math::Sqrt((v1 * v1) + (v2 * v2));
}

void Vector2::Distance(Vector2 ref value1, Vector2 ref value2, float out result)
{
	float v1 = value1.X - value2.X, v2 = value1.Y - value2.Y;
	result = (float)Riccsson::System::Math::Sqrt((v1 * v1) + (v2 * v2));
}

float Vector2::DistanceSquared(Vector2 value1, Vector2 value2)
{
	float v1 = value1.X - value2.X, v2 = value1.Y - value2.Y;
	return (v1 * v1) + (v2 * v2);
}

void Vector2::DistanceSquared(Vector2 ref value1, Vector2 ref value2, float out result)
{
	float v1 = value1.X - value2.X, v2 = value1.Y - value2.Y;
	result = (v1 * v1) + (v2 * v2);
}

Vector2 Vector2::Divide(Vector2 value1, Vector2 value2)
{
	value1.X /= value2.X;
	value1.Y /= value2.Y;
	return value1;
}

void Vector2::Divide(Vector2 ref value1, Vector2 ref value2, Vector2 out result)
{
	result.X = value1.X / value2.X;
	result.Y = value1.Y / value2.Y;
}

Vector2 Vector2::Divide(Vector2 value1, float divider)
{
	float factor = 1 / divider;
	value1.X *= factor;
	value1.Y *= factor;
	return value1;
}

void Vector2::Divide(Vector2 ref value1, float divider, Vector2 out result)
{
	float factor = 1 / divider;
	result.X = value1.X * factor;
	result.Y = value1.Y * factor;
}

float Vector2::Dot(Vector2 value1, Vector2 value2)
{
	return (value1.X * value2.X) + (value1.Y * value2.Y);
}

void Vector2::Dot(Vector2 ref value1, Vector2 ref value2, float out result)
{
	result = (value1.X * value2.X) + (value1.Y * value2.Y);
}

bool Vector2::Equals(object* obj) // object
{
	throw;
}

bool Vector2::Equals(Vector2* obj) // object
{
	if(instanceof_const( obj, Vector2 ))
	{
		return Equals(obj);
	}
			
	return false;
}

Vector2 Vector2::Reflect(Vector2 vector, Vector2 normal)
{
	Vector2 result;
	float val = 2.0f * ((vector.X * normal.X) + (vector.Y * normal.Y));
	result.X = vector.X - (normal.X * val);
	result.Y = vector.Y - (normal.Y * val);
	return result;
}
		
void Vector2::Reflect(Vector2 ref vector, Vector2 ref normal, Vector2 out result)
{
	float val = 2.0f * ((vector.X * normal.X) + (vector.Y * normal.Y));
	result.X = vector.X - (normal.X * val);
	result.Y = vector.Y - (normal.Y * val);
}
		
int Vector2::GetHashCode()
{
	//return X.GetHashCode() + Y.GetHashCode();
	throw;
}

Vector2 Vector2::Hermite(Vector2 value1, Vector2 tangent1, Vector2 value2, Vector2 tangent2, float amount)
{
	Vector2 result = Vector2();
	Hermite(value1, tangent1, value2, tangent2, amount, result);
	return result;
}

void Vector2::Hermite(Vector2 ref value1, Vector2 ref tangent1, Vector2 ref value2, Vector2 ref tangent2, float amount, Vector2 out result)
{
	result.X = MathHelper::Hermite(value1.X, tangent1.X, value2.X, tangent2.X, amount);
	result.Y = MathHelper::Hermite(value1.Y, tangent1.Y, value2.Y, tangent2.Y, amount);
}

float Vector2::Length()
{
	return (float)Riccsson::System::Math::Sqrt((X * X) + (Y * Y));
}

float Vector2::LengthSquared()
{
	return (X * X) + (Y * Y);
}

Vector2 Vector2::Lerp(Vector2 value1, Vector2 value2, float amount)
{
	return Vector2(
		MathHelper::Lerp(value1.X, value2.X, amount),
		MathHelper::Lerp(value1.Y, value2.Y, amount));
}

void Vector2::Lerp(Vector2 ref value1, Vector2 ref value2, float amount, Vector2 out result)
{
	result = Vector2(
		MathHelper::Lerp(value1.X, value2.X, amount),
		MathHelper::Lerp(value1.Y, value2.Y, amount));
}

Vector2 Vector2::Max(Vector2 value1, Vector2 value2)
{
	return Vector2(value1.X > value2.X ? value1.X : value2.X, 
						value1.Y > value2.Y ? value1.Y : value2.Y);
}

void Vector2::Max(Vector2 ref value1, Vector2 ref value2, Vector2 out result)
{
	result.X = value1.X > value2.X ? value1.X : value2.X;
	result.Y = value1.Y > value2.Y ? value1.Y : value2.Y;
}

Vector2 Vector2::Min(Vector2 value1, Vector2 value2)
{
	return Vector2(value1.X < value2.X ? value1.X : value2.X, 
						value1.Y < value2.Y ? value1.Y : value2.Y); 
}

void Vector2::Min(Vector2 ref value1, Vector2 ref value2, Vector2 out result)
{
	result.X = value1.X < value2.X ? value1.X : value2.X;
	result.Y = value1.Y < value2.Y ? value1.Y : value2.Y;
}

Vector2 Vector2::Multiply(Vector2 value1, Vector2 value2)
{
	value1.X *= value2.X;
	value1.Y *= value2.Y;
	return value1;
}

Vector2 Vector2::Multiply(Vector2 value1, float scaleFactor)
{
	value1.X *= scaleFactor;
	value1.Y *= scaleFactor;
	return value1;
}

void Vector2::Multiply(Vector2 ref value1, float scaleFactor, Vector2 out result)
{
	result.X = value1.X * scaleFactor;
	result.Y = value1.Y * scaleFactor;
}

void Vector2::Multiply(Vector2 ref value1, Vector2 ref value2, Vector2 out result)
{
	result.X = value1.X * value2.X;
	result.Y = value1.Y * value2.Y;
}

Vector2 Vector2::Negate(Vector2 value)
{
	value.X = -value.X;
	value.Y = -value.Y;
	return value;
}

void Vector2::Negate(Vector2 ref value, Vector2 out result)
{
	result.X = -value.X;
	result.Y = -value.Y;
}

void Vector2::Normalize()
{
	float val = 1.0f / (float)Riccsson::System::Math::Sqrt((X * X) + (Y * Y));
	X *= val;
	Y *= val;
}

Vector2 Vector2::Normalize(Vector2 value)
{
	float val = 1.0f / (float)Riccsson::System::Math::Sqrt((value.X * value.X) + (value.Y * value.Y));
	value.X *= val;
	value.Y *= val;
	return value;
}

void Vector2::Normalize(Vector2 ref value, Vector2 out result)
{
	float val = 1.0f / (float)Riccsson::System::Math::Sqrt((value.X * value.X) + (value.Y * value.Y));
	result.X = value.X * val;
	result.Y = value.Y * val;
}

Vector2 Vector2::SmoothStep(Vector2 value1, Vector2 value2, float amount)
{
	return Vector2(
		MathHelper::SmoothStep(value1.X, value2.X, amount),
		MathHelper::SmoothStep(value1.Y, value2.Y, amount));
}

void Vector2::SmoothStep(Vector2 ref value1, Vector2 ref value2, float amount, Vector2 out result)
{
	result = Vector2(
		MathHelper::SmoothStep(value1.X, value2.X, amount),
		MathHelper::SmoothStep(value1.Y, value2.Y, amount));
}

Vector2 Vector2::Subtract(Vector2 value1, Vector2 value2)
{
	value1.X -= value2.X;
	value1.Y -= value2.Y;
	return value1;
}

void Vector2::Subtract(Vector2 ref value1, Vector2 ref value2, Vector2 out result)
{
	result.X = value1.X - value2.X;
	result.Y = value1.Y - value2.Y;
}

void Vector2::Transform(Vector2 ref position, Matrix ref matrix, Vector2 out result)
{
	result = Vector2((position.X * matrix.M11) + (position.Y * matrix.M21) + matrix.M41,
							(position.X * matrix.M12) + (position.Y * matrix.M22) + matrix.M42);
}

Vector2 Vector2::Transform(Vector2 position, Quaternion& quat)
{
	Transform(position, quat, position);
	return position;
}

void Vector2::Transform(Vector2 ref position, Quaternion ref quat, Vector2 out result)
{
	Quaternion v = Quaternion(position.X, position.Y, 0, 0);
	Quaternion i;
	Quaternion t;
	Quaternion::Inverse(quat, i);
	Quaternion::Multiply(quat, v, t);
	Quaternion::Multiply(t, i, v);

	result = Vector2(v.X, v.Y);
}
		
Vector2 Vector2::Transform(Vector2 position, Matrix& matrix)
{
	Transform(/*ref*/ position, /*ref*/ matrix, /*out*/ position);
	return position;
}

void Vector2::Transform (
	Riccsson::System::Array<Vector2>* sourceArray,
	Matrix& matrix,
	Riccsson::System::Array<Vector2>* destinationArray)
{
	Transform(sourceArray, 0, matrix, destinationArray, 0, sourceArray->Length);
}

		
void Vector2::Transform (
	Riccsson::System::Array<Vector2>* sourceArray,
	int sourceIndex,
	Matrix& matrix,
	Riccsson::System::Array<Vector2>* destinationArray,
	int destinationIndex,
	int length)
{
	//for (int x = 0; x < length; x++)
	//{
	//	position = sourceArray[sourceIndex + x];
	//	destination = destinationArray[destinationIndex + x];
	//	destination.X = (position.X * matrix.M11) + (position.Y * matrix.M21) + matrix.M41;
	//	destination.Y = (position.X * matrix.M12) + (position.Y * matrix.M22) + matrix.M42;
	//	destinationArray[destinationIndex + x] = destination;
	//}
	throw;
}

Vector2 Vector2::TransformNormal(Vector2 normal, Matrix& matrix)
{
	Vector2::TransformNormal(normal, matrix, normal);
	return normal;
}

void Vector2::TransformNormal(Vector2 ref normal, Matrix ref matrix, Vector2 out result)
{
	result = Vector2((normal.X * matrix.M11) + (normal.Y * matrix.M21),
							(normal.X * matrix.M12) + (normal.Y * matrix.M22));
}

GC_PTR<Riccsson::System::string> Vector2::ToString()
{
	//CultureInfo currentCulture = CultureInfo.CurrentCulture;
    //return Riccsson::System::String::Format(currentCulture, "{{X:{0} Y:{1}}}", object[] { 
	//	this.X.ToString(currentCulture), this.Y.ToString(currentCulture) });
	throw;
}

#pragma endregion Vector2::Methods




//Vector2 operator -(Vector2 value)
//{
//	value.X = -value.X;
//	value.Y = -value.Y;
//	return value;
//}
//
//bool operator ==(const Vector2 value1, const Vector2 value2)
//{
//	return value1.X == value2.X && value1.Y == value2.Y;
//}
//
//
//bool operator !=(Vector2 value1, Vector2 value2)
//{
//	return value1.X != value2.X || value1.Y != value2.Y;
//}
//
//
//Vector2 operator +(Vector2 value1, Vector2 value2)
//{
//	value1.X += value2.X;
//	value1.Y += value2.Y;
//	return value1;
//}
//
//
//Vector2 operator -(Vector2 value1, Vector2 value2)
//{
//	value1.X -= value2.X;
//	value1.Y -= value2.Y;
//	return value1;
//}
//
//
//Vector2 operator *(Vector2 value1, Vector2 value2)
//{
//	value1.X *= value2.X;
//	value1.Y *= value2.Y;
//	return value1;
//}
//
//
//Vector2 operator *(Vector2 value, float scaleFactor)
//{
//	value.X *= scaleFactor;
//	value.Y *= scaleFactor;
//	return value;
//}
//
//
//Vector2 operator *(float scaleFactor, Vector2 value)
//{
//	value.X *= scaleFactor;
//	value.Y *= scaleFactor;
//	return value;
//}
//
//
//Vector2 operator /(Vector2 value1, Vector2 value2)
//{
//	value1.X /= value2.X;
//	value1.Y /= value2.Y;
//	return value1;
//}
//
//
//Vector2 operator /(Vector2 value1, float divider)
//{
//	float factor = 1 / divider;
//	value1.X *= factor;
//	value1.Y *= factor;
//	return value1;
//}